package com.yuxer.mybatisplus.utils;

import cn.hutool.core.util.ObjectUtil;
import org.apache.commons.lang3.time.DateFormatUtils;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.*;
import java.time.format.DateTimeFormatter;
import java.util.Date;
import java.util.List;
import java.util.TimeZone;

/**
 * 自定义的时间工具类
 *
 * @author 醋醋🐟
 */
public class DateUtils {

    public final static TimeZone TIME_ZONE = TimeZone.getTimeZone("Asia/Shanghai");
    public final static String TIME_ZONE_NUM = "GMT+8";
    /**
     * 开始
     */
    public final static String YEAR_START = "20";
    public static final String FORMAT_SLASH = "/";
    public static final String FORMAT_COLON = ":";
    public static final String FORMAT_DASH = "-";

    public static final String FORMAT_PATTERN_ALL_NO = "yyyyMMddHHmmss";
    public static final String FORMAT_PATTERN_ALL_NO_DASH = "yyyy-MM-ddHHmmss";
    public static final String FORMAT_PATTERN_ALL_NO_SLASH = "yyyy/MM/ddHHmmss";
    public static final String FORMAT_PATTERN_ALL = "yyyy-MM-ddHH:mm:ss";
    public static final String FORMAT_PATTERN_ALL_DASH = "yyyy-MM-dd HH:mm:ss";
    public static final String FORMAT_PATTERN_ALL_DASH_T = "yyyy-MM-ddTHH:mm:ss";
    public static final String FORMAT_PATTERN_ALL_SLASH = "yyyy/MM/dd HH:mm:ss";
    public static final String FORMAT_PATTERN_ALL_SLASH_T = "yyyy/MM/ddTHH:mm:ss";
    public static final String FORMAT_PATTERN = "yyyyMMdd";
    public static final String FORMAT_PATTERN_DASH = "yyyy-MM-dd";
    public static final String FORMAT_PATTERN_SLASH = "yyyy/MM/dd";

    public static final String TIME_START = "1970-01-01";


    public static String dateStamp() {
        Date now = new Date();
        return DateFormatUtils.format(now, "yyMMddHHmmss");
    }

    /**
     * 传入日期，匹配格式
     *
     * @param date 日期
     * @return 日期
     */
    public static LocalDateTime parseDateTime(String date) {
        return parseDateTime(date, false);
    }


    /**
     * 传入日期，匹配格式
     *
     * @param date   日期
     * @param isNull 是否允许数据为空
     * @return 日期
     */
    public static LocalDateTime parseDateTime(String date, boolean isNull) {
        if (StrUtils.isEmpty(date)) {
            if (isNull) {
                return null;
            }
            return LocalDateTime.now();
        }
        if (StrUtils.isNum(date)) {
            Instant instant = Instant.ofEpochMilli(Long.parseLong(date));
            return LocalDateTime.ofInstant(instant, ZoneId.systemDefault());
        }
        List<String> patterns = List.of(FORMAT_PATTERN_ALL_NO_DASH, FORMAT_PATTERN_ALL_NO_SLASH,
                FORMAT_PATTERN_ALL, FORMAT_PATTERN_ALL_NO, FORMAT_PATTERN_ALL_DASH, FORMAT_PATTERN_ALL_DASH_T, FORMAT_PATTERN_ALL_SLASH, FORMAT_PATTERN_ALL_SLASH_T);
        for (String pattern : patterns) {
            try {
                return LocalDateTime.parse(date, DateTimeFormatter.ofPattern(pattern));
            } catch (Exception ignored) {
                // 不匹配，继续匹配
            }
        }
        // 如果都没有匹配上，则加上”20“在试试
        for (String pattern : patterns) {
            try {
                String d = YEAR_START + date;
                return LocalDateTime.parse(d, DateTimeFormatter.ofPattern(pattern));
            } catch (Exception ignored) {
                // 不匹配，继续匹配
            }
        }
        if (isNull) {
            return null;
        }
        return LocalDateTime.now();
    }


    /**
     * 传入日期，匹配格式
     *
     * @param date 日期
     * @return 日期
     */
    public static LocalDate parseDateForDay(String date) {
        return parseDateForDay(date, false);
    }

    /**
     * 传入日期，匹配格式
     *
     * @param date 日期
     * @return 日期
     */
    public static LocalDate parseDateForDay(String date, boolean ifNull) {
        if (StrUtils.isEmpty(date)) {
            if (ifNull) {
                return null;
            }
            return LocalDate.now();
        }
        if (StrUtils.isNum(date)) {
            Instant instant = Instant.ofEpochMilli(Long.parseLong(date));
            return LocalDate.ofInstant(instant, ZoneId.systemDefault());
        }
        List<String> patterns = List.of(FORMAT_PATTERN, FORMAT_PATTERN_ALL_NO_DASH, FORMAT_PATTERN_ALL_NO_SLASH,
                FORMAT_PATTERN_ALL, FORMAT_PATTERN_DASH, FORMAT_PATTERN_SLASH,
                FORMAT_PATTERN_ALL_NO, FORMAT_PATTERN_ALL_DASH, FORMAT_PATTERN_ALL_SLASH);
        for (String pattern : patterns) {
            try {
                return LocalDate.parse(date, DateTimeFormatter.ofPattern(pattern));
            } catch (Exception ignored) {
                // 不匹配，继续匹配
            }
        }
        // 如果都没有匹配上，则加上”20“在试试
        for (String pattern : patterns) {
            try {
                String d = YEAR_START + date;
                return LocalDate.parse(d, DateTimeFormatter.ofPattern(pattern));
            } catch (Exception ignored) {
                // 不匹配，继续匹配
            }
        }
        if (ifNull) {
            return null;
        }
        return LocalDate.now();
    }

    /**
     * 获取指定格式的时间字串
     *
     * @param date    时间
     * @param pattern 格式
     * @return 时间字串
     */
    public static String getFormatDate(LocalDateTime date, String pattern) {
        return date.format(DateTimeFormatter.ofPattern(pattern));
    }

    /**
     * 获取一天的结束时间
     * 不传入时间的话就默认 1970
     *
     * @param day 传入时间
     * @return 格式化后的时间
     */
    public static LocalDateTime getStartDateTime(String day) {
        if (StrUtils.isEmpty(day)) {
            return LocalDateTime.of(1970, 1, 1, 0, 0, 0);
        }
        return parseDateTime(day).withHour(0).withMinute(0).withSecond(0).withNano(0);
    }

    /**
     * 获取一天的结束时间
     * 不传入时间的话就默认 2099
     *
     * @param day 传入时间
     * @return 格式化后的时间
     */
    public static LocalDateTime getEndDateTime(String day) {
        if (StrUtils.isEmpty(day)) {
            return LocalDateTime.of(2099, 12, 31, 23, 59, 59);
        }
        return getEndDateForDay(parseDateTime(day));
    }

    /**
     * 获取时间戳
     *
     * @param dateTime 时间
     * @return 时间戳
     */
    public static long getTimestamp(LocalDateTime dateTime) {
        // 转换为ZonedDateTime
        ZonedDateTime zonedDateTime = dateTime.atZone(ZoneId.systemDefault());
        // 转换为Instant
        Instant instant = zonedDateTime.toInstant();
        // 方法1: 使用Duration
        return Duration.between(Instant.EPOCH, instant).toMillis();
    }

    /**
     * 获取进货单模板上的一天
     *
     * @param day 字符串时间
     * @return 标准时间
     */
    public static LocalDateTime getPurchaseTemplateDate(String day) {
        Date date;
        try {
            SimpleDateFormat format = new SimpleDateFormat("dd-MM月-yyyy");
            format.setTimeZone(TIME_ZONE);
            date = format.parse(day);
        } catch (ParseException e) {
            return null;
        }
        Instant instant = date.toInstant();
        return LocalDateTime.ofInstant(instant, ZoneId.systemDefault());
    }

    /**
     * 获取一天的结束时间，如果不传入默认获取今天
     *
     * @param day 传入时间
     * @return 格式化后的时间
     */
    public static LocalDateTime getEndDateForDay(LocalDate day) {
        return day.atStartOfDay().withHour(23).withMinute(59).withSecond(59).withNano(0);
    }

    /**
     * 获取一天最后时刻
     *
     * @param day 时间
     * @return 格式化后的时间
     */
    public static LocalDateTime getEndDateForDay(LocalDateTime day) {
        return day.withHour(23).withMinute(59).withSecond(59).withNano(0);
    }

    /**
     * 获取当月最后一天
     *
     * @param date 时间
     * @return 最后一天
     */
    public static LocalDate getEndDayForMonth(LocalDate date) {
        return date.plusDays(date.lengthOfMonth()).withDayOfMonth(1);
    }

    /**
     * 比对时间（仅精确到天）
     *
     * @param time1 时间1
     * @param time2 时间2
     * @return 是否一样
     */
    public static Integer checkDateSame(LocalDateTime time1, LocalDateTime time2) {
        LocalDate date1 = time1.toLocalDate();
        LocalDate date2 = time2.toLocalDate();
        return date1.compareTo(date2);
    }

    /**
     * 获取过期时间
     *
     * @param productionDate 生产日期
     * @param shelfLife      保质期
     * @return 过期时间
     */
    public static LocalDate getCorruptionDate(LocalDate productionDate, Integer shelfLife) {
        return productionDate.plusDays(shelfLife);
    }


    /**
     * 计算两个日期之间的天数(结果为绝对值)
     *
     * @param startDate 开始时间
     * @param endDate   结束时间
     * @return 天数（包含开始和结束）
     */
    public static Integer getDaysBetweenByAbs(LocalDate startDate, LocalDate endDate) {
        return Math.abs(getDaysBetween(startDate, endDate));
    }

    /**
     * 计算两个日期之间的天数
     *
     * @param bigDate   大时间
     * @param smallDate 小时间
     * @return 天数（包含开始和结束）
     */
    public static Integer getDaysBetween(LocalDate bigDate, LocalDate smallDate) {
        return (int) (bigDate.toEpochDay() - smallDate.toEpochDay());
    }

    /**
     * 检查时间是否已经超过限定时间
     *
     * @param date 传入时间
     * @param day  限定时间（天）
     * @return 是否超限
     */
    public static boolean checkDateOverDay(LocalDate date, int day) {
        if (ObjectUtil.isNull(date)) {
            return true;
        }
        // 计算传入时间到今天已经多少天了
        int i = getDaysBetween(LocalDate.now(), date);
        // 如果是负数，那就是没超过
        if (i <= 0) {
            return false;
        }
        // 期限时间小于等于已产生的差值，那就是超过，否则就是没超过
        return day <= i;
    }

}
